home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Development Kits / MPW etc / MPW-GM / MPW / Examples / PPCExamples / CPlusExamples / CPlusTESample / TESample.cp < prev    next >
Encoding:
Text File  |  1998-12-03  |  13.8 KB  |  489 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple TextEdit Sample Application
  6. #
  7. #    CPlusTESample
  8. #
  9. #    TESample.cp    -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/91
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #
  19. #    Components:
  20. #            CPlusTESample.make        July 9, 1989
  21. #            TApplicationCommon.h    July 9, 1989
  22. #            TApplication.h            July 9, 1989
  23. #            TDocument.h                July 9, 1989
  24. #            TECommon.h                July 9, 1989
  25. #            TESample.h                July 9, 1989
  26. #            TEDocument.h            July 9, 1989
  27. #            TESample.cp                July 9, 1989
  28. #            TESample.r                July 9, 1989
  29. #
  30. #    CPlusTESample is an example application that demonstrates
  31. #    how to initialize the commonly used toolbox managers,
  32. #    operate successfully under MultiFinder, handle desk
  33. #    accessories and create, grow, and zoom windows. The
  34. #    fundamental TextEdit toolbox calls and TextEdit autoscroll
  35. #    are demonstrated. It also shows how to create and maintain
  36. #    scrollbar controls. 
  37. #
  38. #    This version of TESample has been substantially reworked in
  39. #    C++ to show how a "typical" object oriented program could
  40. #    be written. To this end, what was once a single source code
  41. #    file has been restructured into a set of classes which
  42. #    demonstrate the advantages of object-oriented programming.
  43. #
  44. ------------------------------------------------------------------------------*/
  45.  
  46.  
  47. /*
  48. Segmentation strategy:
  49.  
  50.     This program has only one segment, since the issues
  51.     surrounding segmentation within a class's methods have
  52.     not been investigated yet. We DO unload the data
  53.     initialization segment at startup time, which frees up
  54.     some memory 
  55.  
  56. SetPort strategy:
  57.  
  58.     Toolbox routines do not change the current port. In
  59.     spite of this, in this program we use a strategy of
  60.     calling SetPort whenever we want to draw or make calls
  61.     which depend on the current port. This makes us less
  62.     vulnerable to bugs in other software which might alter
  63.     the current port (such as the bug (feature?) in many
  64.     desk accessories which change the port on OpenDeskAcc).
  65.     Hopefully, this also makes the routines from this
  66.     program more self-contained, since they don't depend on
  67.     the current port setting. 
  68.  
  69. Clipboard strategy:
  70.  
  71.     This program does not maintain a private scrap.
  72.     Whenever a cut, copy, or paste occurs, we import/export
  73.     from the public scrap to TextEdit's scrap right away,
  74.     using the TEToScrap and TEFromScrap routines. If we did
  75.     use a private scrap, the import/export would be in the
  76.     activate/deactivate event and suspend/resume event
  77.     routines. 
  78. */
  79.  
  80. #include <Types.h>
  81. #include <Quickdraw.h>
  82. #include <Fonts.h>
  83. #include <Controls.h>
  84. #include <Windows.h>
  85. #include <TextEdit.h>
  86. #include <Dialogs.h>
  87. #include <Menus.h>
  88. #include <Devices.h>
  89. #include <Events.h> 
  90. #include <Scrap.h>
  91. #include <ToolUtils.h>
  92. #include <Memory.h>
  93. #include <SegLoad.h>
  94. #include <Files.h>
  95. #include <OSUtils.h>
  96. #include <Traps.h>
  97.  
  98. // our class definitions
  99. #include "TEDocument.h"
  100. #include "TESample.h"
  101.  
  102. // ExtremeNeg and ExtremePos are used to set up wide open rectangles and regions.
  103. const short kExtremeNeg = -32768;
  104. const short kExtremePos = 32767 - 1; // required to address an old region bug
  105.  
  106. // kMaxOpenDocuments is used to determine whether a new document can be opened
  107. // or created. We keep track of the number of open documents, and disable the
  108. // menu items that create a new document when the maximum is reached. If the
  109. // number of documents falls below the maximum, the items are enabled again. */
  110. const short    kMaxOpenDocuments = 1;
  111.     
  112. // Define max and min macros for efficiency.
  113. #define max(a,b)        ((a) > (b) ? (a) : (b))
  114. #define min(a,b)        ((a) < (b) ? (a) : (b))
  115.  
  116. // Our application object, initialized in main(). We make it
  117. // global so our functions which don't belong to any class
  118. // can find the active document.
  119.     TESample *gTheApplication;
  120.  
  121.  
  122.  
  123. /***********************************************************************/
  124. //
  125. // TESample
  126. //
  127. /***********************************************************************/
  128.  
  129. //-----------------------------------------------------------------------
  130. // main -    main is the entrypoint to the program
  131. // 
  132.     int main( void )
  133.     {
  134.         // Create our application object. This MUST be the FIRST thing
  135.         // done in main(), since it initializes the Toolbox for us.
  136.             gTheApplication = new TESample;
  137.             if (gTheApplication == nil)                        // if we couldn't allocate object (impossible!?)
  138.                 return 0;                                    // go back to Finder
  139.         
  140.         // Start our main event loop running. This won't return until user quits
  141.             gTheApplication->EventLoop();
  142.     
  143.         // We always return a value, like good little ANSI worshippers
  144.             return 0;
  145.             
  146.     } /* main */
  147.  
  148.  
  149.  
  150. /***********************************************************************/
  151. //
  152. // TESample class declarations
  153. //
  154. /***********************************************************************/
  155.  
  156. //-----------------------------------------------------------------------
  157. // TESample::TESample -    the constructor for our class, called automatically when we create
  158. //                         an instance of this class. In this particular case, we only want
  159. //                         one instance since the constructor does all the menu setups and
  160. //                         creates our (untitled) document.
  161. //
  162.     TESample::TESample( void )
  163.     {
  164.         Handle    menuBar;
  165.     
  166.         // read menus into menu bar
  167.             menuBar = GetNewMBar(rMenuBar);
  168.             
  169.         // install menus
  170.             SetMenuBar(menuBar);
  171.             DisposeHandle(menuBar);
  172.             
  173.         // add DA names to Apple menu
  174.             AppendResMenu(GetMenuHandle(mApple), 'DRVR');
  175.             DrawMenuBar();
  176.     
  177.         // create empty mouse region
  178.             fMouseRgn = NewRgn();
  179.             
  180.         // create a single empty document
  181.             DoNew();
  182.         
  183.         // make sure we have a valid cursor region
  184.             AdjustCursor();
  185.             
  186.     } /* TESample (constructor) */
  187.  
  188.  
  189. //-----------------------------------------------------------------------
  190. // TESample::HeapNeeded -    Tell TApplication class how much heap we need
  191. //
  192.     long TESample::HeapNeeded( void )
  193.     {
  194.         return ( kMinSize * 1024 );
  195.         
  196.     } /* TESample::HeapNeeded */
  197.  
  198.  
  199. //-----------------------------------------------------------------------
  200. // TESample::HeapNeeded -    Calculate a sleep value for WaitNextEvent. This
  201. //                            takes into account the things that DoIdle does
  202. //                            with idle time.
  203. //
  204.     unsigned long TESample::SleepVal( void )
  205.     {
  206.         unsigned long sleep;
  207.     
  208.         sleep = kMaxSleepTime;                // default value for sleep
  209.         
  210.         // if we aren't in background, let document tell us how long to sleep
  211.             if (( !fInBackground ) && ( fCurDoc != nil ))
  212.                 sleep = min( sleep, fCurDoc->CalcIdle());
  213.                 
  214.             return sleep;
  215.         
  216.     } /* TESample::SleepVal */
  217.  
  218.  
  219. //-----------------------------------------------------------------------
  220. // TESample::DoIdle -    This is called whenever we get a null event et al.
  221. //                         It takes care of necessary periodic actions. For this program,
  222. //                         it calls TEIdle.
  223. //
  224.     void TESample::DoIdle( void )
  225.     {
  226.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  227.     
  228.         if ( fTECurDoc != nil )
  229.             fTECurDoc->DoIdle();
  230.           
  231.     } /* TESample::DoIdle */
  232.  
  233.  
  234. //-----------------------------------------------------------------------
  235. // TESample::AdjustCursor -    This is called whenever we get a null event et al.
  236. //                             Change the cursor's shape, depending on its position.
  237. //                            This also calculates a region that includes the
  238. //                            cursor for WaitNextEvent.
  239. //
  240.     void TESample::AdjustCursor( void )
  241.     {
  242.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  243.     
  244.         // notice that we don't change cursor if front window isn't ours
  245.             if (( !fInBackground ) && ( fTECurDoc != nil ))
  246.               {
  247.                 RgnHandle    arrowRgn;
  248.                 RgnHandle    iBeamRgn;
  249.                 Point        mouse;
  250.                 
  251.                 // get mouse location and convert to global coordinates
  252.                     GetMouse( &mouse );
  253.                     LocalToGlobal( &mouse );
  254.         
  255.                 // calculate regions for different cursor shapes
  256.                     arrowRgn = NewRgn();
  257.                     iBeamRgn = NewRgn();
  258.                 
  259.                 // start arrowRgn wide open
  260.                     SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  261.                     
  262.                 // calculate iBeamRgn
  263.                     fTECurDoc->GetVisTERgn( iBeamRgn );
  264.                     
  265.                 // subtract iBeamRgn from arrowRgn 
  266.                     DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  267.         
  268.                 // change the cursor and the region parameter 
  269.                     if ( PtInRgn(mouse, iBeamRgn ))
  270.                     {
  271.                         SetCursor( *GetCursor( iBeamCursor ));
  272.                         CopyRgn( iBeamRgn, fMouseRgn );
  273.                     }
  274.                     else
  275.                     {
  276.                         SetCursor( &qd.arrow );
  277.                         CopyRgn( arrowRgn, fMouseRgn );
  278.                     }
  279.                     
  280.                 // get rid of regions we don't need anymore
  281.                     DisposeRgn( arrowRgn );
  282.                     DisposeRgn( iBeamRgn );
  283.               }
  284.     } /* TESample::AdjustCursor */
  285.  
  286.  
  287. //-----------------------------------------------------------------------
  288. // TESample::AdjustMenus -    Enable and disable menus based on the current state.
  289. //                             The user can only select enabled menu items. We set
  290. //                            up all the menu items before calling MenuSelect or
  291. //                            MenuKey, since these are the only times that a menu
  292. //                            item can be selected. Note that MenuSelect is also
  293. //                            the only time the user will see menu items. This
  294. //                            approach to deciding what enable/disable state a
  295. //                            menu item has the advantage of concentrating all the
  296. //                            decision-making in one routine, as opposed to being
  297. //                            spread throughout the application. Other application
  298. //                            designs may take a different approach that may or may
  299. //                            not be as valid. 
  300. //
  301.     void TESample::AdjustMenus( void )
  302.     {
  303.         WindowPtr    frontmost;
  304.         MenuHandle    menu;
  305.         long        offset;
  306.         Boolean        undo;
  307.         Boolean        cutCopyClear;
  308.         Boolean        paste;
  309.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  310.     
  311.         frontmost = FrontWindow();
  312.     
  313.         menu = GetMenuHandle( mFile );
  314.         if ( fDocList->NumDocs() < kMaxOpenDocuments )    // New is enabled when we can open more documents 
  315.             EnableItem( menu, iNew );                    
  316.         else
  317.             DisableItem( menu, iNew );
  318.         
  319.         if ( frontmost != (WindowPtr) nil )                // Close is enabled when there is a window to close 
  320.             EnableItem( menu, iClose );
  321.         else
  322.             DisableItem( menu, iClose );
  323.     
  324.         menu = GetMenuHandle( mEdit );
  325.         undo = false;
  326.         cutCopyClear = false;
  327.         paste = false;
  328.         
  329.         if ( frontmost != nil )
  330.         {
  331.             if ( fTECurDoc == nil )
  332.             {
  333.                 undo = true;                            // all editing is enabled for DA windows 
  334.                 cutCopyClear = true;
  335.                 paste = true;
  336.             }
  337.             else
  338.             {
  339.                 // Cut, Copy, and Clear is enabled for app. windows with selections 
  340.                     if ( fTECurDoc->HaveSelection())
  341.                         cutCopyClear = true;
  342.                     
  343.                 // If we have any TEXT in the scrap, enable paste
  344.                     if ( GetScrap( nil, 'TEXT', &offset ))
  345.                         paste = true; 
  346.             }
  347.         }
  348.         
  349.         if ( undo )
  350.             EnableItem( menu, iUndo );
  351.         else
  352.             DisableItem( menu, iUndo );
  353.             
  354.         if ( cutCopyClear )
  355.         {
  356.             EnableItem( menu, iCut );
  357.             EnableItem( menu, iCopy );
  358.             EnableItem( menu, iClear );
  359.         } 
  360.         else
  361.         {
  362.             DisableItem( menu, iCut );
  363.             DisableItem( menu, iCopy );
  364.             DisableItem( menu, iClear );
  365.         }
  366.         
  367.         if ( paste )
  368.             EnableItem( menu, iPaste );
  369.         else
  370.             DisableItem( menu, iPaste );
  371.             
  372.     } /* TESample::AdjustMenus */
  373.  
  374.  
  375. //-----------------------------------------------------------------------
  376. // TESample::DoMenuCommand -    This is called when an item is chosen from the 
  377. //                                menu bar (after calling MenuSelect or MenuKey).
  378. //                                It does the right thing for each command.
  379. //
  380.     void TESample::DoMenuCommand( short menuID, short menuItem )
  381.     {
  382.         short        itemHit;
  383.         Str255        daName;
  384.         short        daRefNum;
  385.         WindowPtr    window;
  386.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  387.     
  388.         window = FrontWindow();
  389.         switch ( menuID )
  390.         {
  391.             case mApple:    switch ( menuItem )
  392.                             {
  393.                                 case iAbout:    itemHit = Alert( rAboutAlert, nil );                    // bring up alert for About 
  394.                                                 break;
  395.                                     
  396.                                 default:        GetMenuItemText( GetMenuHandle(mApple), menuItem, daName );        // all non-About items in this menu are DAs et al 
  397.                                                 daRefNum = OpenDeskAcc( daName );
  398.                                                 break;
  399.                             }
  400.                             break;
  401.                             
  402.             case mFile:        switch ( menuItem )
  403.                             {
  404.                                 case iNew:        DoNew();
  405.                                                 break;
  406.                                                 
  407.                                 case iClose:    if (fTECurDoc != nil)
  408.                                                 {
  409.                                                     fDocList->RemoveDoc( fTECurDoc );
  410.                                                     fTECurDoc->DoClose();
  411.                                                 }
  412.                                                 else
  413.                                                     CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind );
  414.                                                     
  415.                                                 // make sure our current document/window references are valid
  416.                                                     fWhichWindow = FrontWindow();
  417.                                                     if ( fWhichWindow != nil )
  418.                                                     {
  419.                                                         fCurDoc = fDocList->FindDoc( fWhichWindow );
  420.                                                         SetPort( fWhichWindow );
  421.                                                     }
  422.                                                     else
  423.                                                         fCurDoc = nil;
  424.                                                 break;
  425.                                                 
  426.                                 case iQuit:        Terminate();
  427.                                                 break;
  428.                             }
  429.                             break;
  430.                             
  431.             case mEdit:        if ( !SystemEdit( menuItem-1 ))                            // call SystemEdit for DA editing & MultiFinder 
  432.                             {
  433.                                 switch ( menuItem )
  434.                                 {
  435.                                     case iCut:        fTECurDoc->DoCut();
  436.                                                     break;
  437.                                                 
  438.                                     case iCopy:        fTECurDoc->DoCopy();
  439.                                                     break;
  440.                                                 
  441.                                     case iPaste:    fTECurDoc->DoPaste();
  442.                                                     break;
  443.                                                     
  444.                                     case iClear:    fTECurDoc->DoClear();
  445.                                                     break;
  446.                                 }
  447.                             }
  448.                             break;
  449.             
  450.             case mDebug:    
  451.                             DebugStr ((ConstStr255Param) "\pEntering Debugger...");
  452.                             break;
  453.                             
  454.         }
  455.         HiliteMenu( 0 );    // unhighlight what MenuSelect (or MenuKey) hilited 
  456.         
  457.     } /* TESample::DoMenuCommand */
  458.  
  459.  
  460. //-----------------------------------------------------------------------
  461. // TESample::DoNew -    Create a new document and window. 
  462. //
  463.     void TESample::DoNew( void )
  464.     {
  465.         TEDocument* tDoc;
  466.     
  467.         tDoc = new TEDocument( rDocWindow );
  468.         
  469.         // if we didn't get an allocation error, add it to list
  470.             if ( tDoc != nil )
  471.                 fDocList->AddDoc( tDoc );
  472.             else
  473.                 AlertUser( kTEDocErrStrings, eNoWindow );
  474.             
  475.     } /* TESample::DoNew */
  476.  
  477.  
  478. //-----------------------------------------------------------------------
  479. // TESample::Terminate -    Clean up the application and exits. You might
  480. //                            want to close all of your documents (and ask
  481. //                            the user to save them) here.
  482. //
  483.     void TESample::Terminate( void )
  484.     {
  485.         ExitLoop();
  486.         
  487.     } /* TESample::Terminate */
  488.  
  489.